/**
 * @file ActorManager.cpp
 *
 * @date 06/02/2012
 * @author Tales 
 *
 */

#include "ActorManager.hpp"
#include "Engine.hpp"
#include "Actor.hpp"
#include "Event.hpp"
#include "CollisionEvent.hpp"
#include "errors.hpp"

namespace wolf {
ActorManager *ActorManager::instance = NULL;

ActorManager::ActorManager() {
	if(instance)
		throw SingletonError("Singleton violation on ActorManager");
	instance = this;
	Engine::getInstance().addManager(*instance);
}

ActorManager::~ActorManager() {
	instance = NULL;
}

void ActorManager::onSetup(Engine & engine) {
}

void ActorManager::onCleanup(Engine & engine) {
}

void ActorManager::onStartFrame(Engine & engine) {
	//Frame Start
	for (map<Actor*, mpFrameHandler>::iterator it = frameStartHandlers.begin();
			it != frameStartHandlers.end(); ++it) {
		Actor &actor(*it->first);
		mpFrameHandler handler = it->second;
		Event event(engine, actor);
		(actor.*handler)(event);
	}
	//Refreshing the position (moving by velocity)
	WOLF_FOR(list<Actor*>, actors, it) {
		Actor &currentActor(**it);
		currentActor.doFrame();
	}
}

void ActorManager::onFrame(Engine & engine) {

	//Frame Events
	for (map<Actor*, mpFrameHandler>::iterator it = frameHandlers.begin();
			it != frameHandlers.end(); ++it) {
		Actor &actor(*it->first);
		mpFrameHandler handler = it->second;
		Event event(engine, actor);
		(actor.*handler)(event);
	}
	//Reserved for collision events
	for (map<Actor*, mpCollisionHandler>::iterator it =
			collisionHandlers.begin(); it != collisionHandlers.end(); ++it) {
		Actor &actorA(*it->first);
		map<Actor*, mpCollisionHandler>::iterator jt = it;
		for (++jt; jt != collisionHandlers.end(); ++jt) {
			Actor &actorB(*jt->first);
			if (actorA.collides(actorB)) {
				mpCollisionHandler handlerA = it->second;
				mpCollisionHandler handlerB = jt->second;
				CollisionEvent eventA(engine, actorA, actorB);
				(actorA.*handlerA)(eventA);
				CollisionEvent eventB(engine, actorB, actorA);
				(actorB.*handlerB)(eventB);
			}
		}
	}
	//End Frame Events
	for (map<Actor*, mpFrameHandler>::iterator it = frameEndHandlers.begin();
			it != frameEndHandlers.end(); ++it) {
		Actor &actor(*it->first);
		mpFrameHandler handler = it->second;
		Event event(engine, actor);
		(actor.*handler)(event);
	}
}

bool ActorManager::onEvent(Engine & engine, SDL_Event & event) {
	return true;
}

ActorManager & ActorManager::getInstance() {
	if (!instance)
		new ActorManager();
	return *instance;
}

void ActorManager::addActor(Actor & actor) {
	actors.push_back(&actor);
}

void ActorManager::removeActor(Actor & actor) {
	actors.remove(&actor);
	frameHandlers.erase(&actor);
	frameStartHandlers.erase(&actor);
	frameEndHandlers.erase(&actor);
	collisionHandlers.erase(&actor);
}

////////////////////
// Event Handlers //
////////////////////

/******************
 * Frame handlers *
 ******************/
void ActorManager::connectFrame(Actor & actor, mpFrameHandler method) {
	frameHandlers[&actor] = method;
}

void ActorManager::disconnectFrame(Actor & actor) {
	frameHandlers.erase(&actor);
}

void ActorManager::connectStartFrame(Actor & actor, mpFrameHandler method) {
	frameStartHandlers[&actor] = method;
}

void ActorManager::disconnectStartFrame(Actor & actor) {
	frameStartHandlers.erase(&actor);
}

void ActorManager::connectEndFrame(Actor & actor, mpFrameHandler method) {
	frameEndHandlers[&actor] = method;
}

void ActorManager::disconnectEndFrame(Actor & actor) {
	frameEndHandlers.erase(&actor);
}

/**********************
 * Collision handlers *
 **********************/
void ActorManager::connectCollision(Actor & actor, mpCollisionHandler method) {
	collisionHandlers[&actor] = method;
}

void ActorManager::disconnectCollision(Actor & actor) {
	collisionHandlers.erase(&actor);
}

} /* namespace wolf */
